

#include <random>
#include "lua_lucky.h"

/********************************************************************************/

typedef long long longint;

static std::mt19937& G19937(){
  static thread_local std::random_device rd;
  static thread_local std::mt19937 gen(rd());
  return gen;
}

static longint max_value(longint v1, longint v2) {
  return v1 > v2 ? v1 : v2;
}

static longint rand_int(longint v1, longint v2){
  std::uniform_int_distribution<longint> dis(v1, v2);
  return (longint)dis(G19937());
}

static int luac_lucky(lua_State* L) {
  longint money = luaL_checkunsigned(L, 1);
  longint count = luaL_checkunsigned(L, 2);
  if (money < 1) {
    lua_pushinteger(L, 0);
    lua_pushinteger(L, 0);
    lua_pushinteger(L, 0);
    return 3;
  }
  if (count < 1){
    lua_pushinteger(L, 0);
    lua_pushinteger(L, money);
    lua_pushinteger(L, 0);
    return 3;
  }
  longint average = money / count;
  if (count > 1){
    longint min_v = average ? 1 : 0;
    longint max_v = max_value(1, average * 2 - 1);
    longint delta = min_v ? 1 : count / money;
    average = rand_int(min_v, max_v * delta) / delta;
  }
  money -= average;
  count -= 1;
  lua_pushinteger(L, average);
  lua_pushinteger(L, money);
  lua_pushinteger(L, count);
  return 3;
}

/********************************************************************************/

LUAOS_API int luaopen_lucky(lua_State* L) {
  const luaL_Reg methods[] = {
    { "lucky",    luac_lucky  },
    { NULL,       NULL        }
  };
  return new_module(L, "math", methods);
}

/********************************************************************************/
